home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / archiver / arc.zoo / arcpack.c < prev    next >
C/C++ Source or Header  |  1989-01-29  |  7KB  |  279 lines

  1. /*
  2.  * $Header: arcpack.c,v 1.12 88/11/16 17:18:06 hyc Exp $
  3.  */
  4.  
  5. /*  ARC - Archive utility - ARCPACK
  6.  
  7.     Version 3.49, created on 04/21/87 at 11:26:51
  8.  
  9. (C) COPYRIGHT 1985-87 by System Enhancement Associates; ALL RIGHTS RESERVED
  10.  
  11.     By:     Thom Henderson
  12.  
  13.     Description:
  14.      This file contains the routines used to compress a file
  15.      when placing it in an archive.
  16.  
  17.     Language:
  18.      Computer Innovations Optimizing C86
  19. */
  20. #include <stdio.h>
  21. #include "arc.h"
  22. #if    MTS
  23. #include <ctype.h>
  24. #endif
  25.  
  26. void    setcode(), sqinit_cm(), sqputc_cm(), init_cm(), putc_cm();
  27. void    filecopy(), abort(), putc_tst(), init_sq(), scan_sq();
  28. int    getch(), addcrc();
  29.  
  30. /* stuff for non-repeat packing */
  31.  
  32. #define DLE 0x90        /* repeat sequence marker */
  33.  
  34. static unsigned char state;    /* current packing state */
  35.  
  36. /* non-repeat packing states */
  37.  
  38. #define NOHIST  0        /* don't consider previous input */
  39. #define SENTCHAR 1        /* lastchar set, no lookahead yet */
  40. #define SENDNEWC 2        /* run over, send new char next */
  41. #define SENDCNT 3        /* newchar set, send count next */
  42.  
  43. /* packing results */
  44.  
  45. static long     stdlen;        /* length for standard packing */
  46. static short    crcval;        /* CRC check value */
  47.  
  48. void
  49. pack(f, t, hdr)            /* pack file into an archive */
  50.     FILE           *f, *t;    /* source, destination */
  51.     struct heads   *hdr;    /* pointer to header data */
  52. {
  53.     int             c;    /* one character of stream */
  54.     long            ncrlen;    /* length after packing */
  55.     long        huflen;    /* length after squeezing */
  56.     long            lzwlen;    /* length after crunching */
  57.     long        pred_sq(), file_sq();    /* stuff for squeezing */
  58.     long            pred_cm(), sqpred_cm();    /* dynamic crunching cleanup */
  59.     long            tloc;   /* start of output */
  60. #ifndef __STDC__
  61.     long        ftell();    
  62. #endif
  63.     int        getch();
  64.     int             getc_ncr();
  65.     void            putc_pak();
  66.  
  67.     /* first pass - see which method is best */
  68.  
  69.     tloc = ftell(t);    /* note start of output */
  70.  
  71.     if (!nocomp) {        /* if storage kludge not active */
  72.         if (note) {
  73.             printf(" analyzing, ");
  74.             fflush(stdout);
  75.         }
  76.         state = NOHIST;    /* initialize ncr packing */
  77.         stdlen = ncrlen = 0;    /* reset size counters */
  78.         crcval = 0;    /* initialize CRC check value */
  79.         setcode();    /* initialize encryption */
  80.         init_sq();    /* initialize for squeeze scan */
  81.  
  82.         if (dosquash) {
  83.             sqinit_cm();
  84.             while ((c = getch(f)) != EOF) {    /* for each byte of file */
  85.                 ncrlen++;    /* one more packed byte */
  86.                 scan_sq(c);    /* see what squeezing can do */
  87.                 sqputc_cm(c, t);    /* see what squashing
  88.                              * can do */
  89.             }
  90.             lzwlen = sqpred_cm(t);
  91.         } else {
  92.             init_cm(t);    /* initialize for crunching */
  93.     
  94.             while ((c = getc_ncr(f)) != EOF) {    /* for each byte of file */
  95.                 ncrlen++;    /* one more packed byte */
  96.                 scan_sq(c);    /* see what squeezing can do */
  97.                 putc_cm(c, t);    /* see what crunching can do */
  98.             }
  99.             lzwlen = pred_cm(t);    /* finish up after crunching */
  100.         }
  101.         huflen = pred_sq();    /* finish up after squeezing */
  102.     } else {        /* else kludge the method */
  103.         stdlen = 0;    /* make standard look best */
  104.         ncrlen = huflen = lzwlen = 1;
  105.     }
  106.  
  107.     /* standard set-ups common to all methods */
  108.  
  109.     fseek(f, 0L, 0);    /* rewind input */
  110.     hdr->crc = crcval;    /* note CRC check value */
  111.     hdr->length = stdlen;    /* set actual file length */
  112.     state = NOHIST;        /* reinitialize ncr packing */
  113.     setcode();        /* reinitialize encryption */
  114.  
  115.     /* choose and use the shortest method */
  116.  
  117.     if (kludge && note)
  118.         printf("\n\tS:%ld  P:%ld  S:%ld  C:%ld,\t ",
  119.             stdlen, ncrlen, huflen, lzwlen);
  120.  
  121.     if (stdlen <= ncrlen && stdlen <= huflen && stdlen <= lzwlen) {
  122.         if (note) {
  123.             printf("storing, ");    /* store without compression */
  124.             fflush(stdout);
  125.         }
  126.         hdrver = 2;    /* note packing method */
  127.         fseek(t, tloc, 0);    /* reset output for new method */
  128.         stdlen = crcval = 0;    /* recalc these for kludge */
  129.         while ((c = getch(f)) != EOF)    /* store it straight */
  130.             putc_pak(c, t);
  131.         hdr->crc = crcval;
  132.         hdr->length = hdr->size = stdlen;
  133.     } else if (ncrlen < lzwlen && ncrlen < huflen) {
  134.         if (note) {
  135.             printf("packing, ");    /* pack with repeat */
  136.             fflush(stdout);        /* suppression */
  137.         }
  138.         hdrver = 3;    /* note packing method */
  139.         hdr->size = ncrlen;    /* set data length */
  140.         fseek(t, tloc, 0);    /* reset output for new method */
  141.         while ((c = getc_ncr(f)) != EOF)
  142.             putc_pak(c, t);
  143.     } else if (huflen < lzwlen) {
  144.         if (note) {
  145.             printf("squeezing, ");
  146.             fflush(stdout);
  147.         }
  148.         hdrver = 4;    /* note packing method */
  149.         fseek(t, tloc, 0);    /* reset output for new method */
  150.         hdr->size = file_sq(f, t);    /* note final size */
  151.     } else {
  152.         if (note)
  153.             printf(dosquash ? "squashed, " : "crunched, ");
  154.         hdrver = dosquash ? 9 : 8;
  155.         hdr->size = lzwlen;    /* size should not change */
  156.     }
  157.  
  158.     /* standard cleanups common to all methods */
  159.  
  160.     if (note)
  161.         printf("done. (%ld%%)\n",hdr->length == 0 ?
  162.                 0L : 100L - (100L*hdr->size)/hdr->length);
  163. }
  164.  
  165. /*
  166.  * Non-repeat compression - text is passed through normally, except that a
  167.  * run of more than two is encoded as:
  168.  * 
  169.  * <char> <DLE> <count>
  170.  * 
  171.  * Special case: a count of zero indicates that the DLE is really a DLE, not a
  172.  * repeat marker.
  173.  */
  174.  
  175. int
  176. getc_ncr(f)            /* get bytes with collapsed runs */
  177.     FILE           *f;    /* file to get from */
  178. {
  179.     static int      lastc;    /* value returned on last call */
  180.     static int      repcnt;    /* repetition counter */
  181.     static int      c;    /* latest value seen */
  182.  
  183.     switch (state) {    /* depends on our state */
  184.     case NOHIST:        /* no relevant history */
  185.         state = SENTCHAR;
  186.         return lastc = getch(f);    /* remember the value next
  187.                          * time */
  188.  
  189.     case SENTCHAR:        /* char was sent. look ahead */
  190.         switch (lastc) {/* action depends on char */
  191.         case DLE:    /* if we sent a real DLE */
  192.             state = NOHIST;    /* then start over again */
  193.             return 0;    /* but note that the DLE was real */
  194.  
  195.         case EOF:    /* EOF is always a special case */
  196.             return EOF;
  197.  
  198.         default:    /* else test for a repeat */
  199.             for (repcnt = 1; (c = getch(f)) == lastc && repcnt < 255; repcnt++);
  200.             /* find end of run */
  201.  
  202.             switch (repcnt) {    /* action depends on run size */
  203.             case 1:/* not a repeat */
  204.                 return lastc = c;    /* but remember value
  205.                              * next time */
  206.  
  207.             case 2:/* a repeat, but too short */
  208.                 state = SENDNEWC;    /* send the second one
  209.                              * next time */
  210.                 return lastc;
  211.  
  212.             default:    /* a run - compress it */
  213.                 state = SENDCNT;    /* send repeat count
  214.                              * next time */
  215.                 return DLE;    /* send repeat marker this
  216.                          * time */
  217.             }
  218.         }
  219.  
  220.     case SENDNEWC:        /* send second char of short run */
  221.         state = SENTCHAR;
  222.         return lastc = c;
  223.  
  224.     case SENDCNT:        /* sent DLE, now send count */
  225.         state = SENDNEWC;
  226.         return repcnt;
  227.  
  228.     default:
  229.         abort("Bug - bad ncr state\n");
  230.     }
  231. }
  232.  
  233. int
  234. getch(f)            /* special get char for packing */
  235.     FILE           *f;    /* file to get from */
  236. {
  237.     int        c;    /* a char from the file */
  238. #if    !DOS
  239.     static int      cr = 0;    /* add \r before \n ? */
  240.  
  241.     if (cr) {
  242.         c = '\n';
  243. #if    MTS
  244.         c = toascii(c);
  245. #endif
  246.         crcval = addcrc(crcval, c);
  247.         stdlen++;
  248.         cr = 0;
  249.         return (c);
  250.     }
  251. #endif
  252.  
  253.     if ((c = fgetc(f)) != EOF) {    /* if not the end of file */
  254. #if    !DOS
  255.         if (!image && (c == '\n')) {
  256.             c = '\r';
  257.             cr = 1;
  258.         }
  259. #endif
  260. #if    MTS
  261.         if (!image)
  262.             c = toascii(c);
  263. #endif
  264.         crcval = addcrc(crcval, c);    /* then update CRC check
  265.                          * value */
  266.         stdlen++;    /* and bump length counter */
  267.     }
  268.     return c;
  269. }
  270.  
  271. void
  272. putc_pak(c, f)            /* put a packed byte into archive */
  273.     char            c;    /* byte to put */
  274.     FILE           *f;    /* archive to put it in */
  275. {
  276.     unsigned char        code();
  277.     putc_tst(code(c), f);    /* put encoded byte, with checks */
  278. }
  279.